package com.intelligent.ispc.web.controller;

import com.intelligent.ispc.common.dto.JsonResponseDto;
import com.intelligent.ispc.common.mapper.JsonMapper;
import com.intelligent.ispc.common.utils.ApplicationException;
import com.intelligent.ispc.common.utils.ExceptionMessages;
import com.intelligent.ispc.common.web.ProcessEvent;
import com.intelligent.ispc.common.web.ProcessInfo;
import com.intelligent.ispc.common.web.Servlets;
import com.intelligent.ispc.core.dto.*;
import com.intelligent.ispc.core.entity.TestData;
import com.intelligent.ispc.core.service.GRRDataIOService;
import com.intelligent.ispc.core.service.GRRTestDataService;
import com.intelligent.ispc.core.service.ProjectService;
import com.intelligent.ispc.core.service.SecurityService;
import com.intelligent.ispc.utils.Constant;
import com.intelligent.ispc.web.utils.ApplicationUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Peter on 2016/6/1.
 */
@Controller
@RequestMapping(value = "/analysis/grr")
public class GRRController {

    @Autowired
    private GRRTestDataService grrTestDataService;

    @Autowired
    private ProjectService projectService;

    @Autowired
    private GRRDataIOService grrDataIOService;

    @Autowired
    private SimpMessagingTemplate msgTemplate;

    @Autowired
    private SecurityService securityService;

    private long fileSize;
    private long readSize;

    @RequestMapping(value = "", method = RequestMethod.GET)
    public String main(Model model) {
        Subject subject = SecurityUtils.getSubject();
        if (!subject.isPermitted("analysis:grr:view")) {
            return "error/noPermission";
        }
        return "analysis/grr/grrAnalysis";
    }

    @ResponseBody
    @RequestMapping(value = "/getGrrItem")
    public JsonResponseDto mainData(ServletRequest request, Model model) {
        List<String> list = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");
            list = grrTestDataService.searchDistinctGRRName(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(list);
    }

    @ResponseBody
    @RequestMapping(value = "/getPSInfo")
    public JsonResponseDto psGrrInfo(ServletRequest request, Model model) {
        PSGRRDto dto = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }
            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");
            dto = projectService.findPSGRRByProject(searchParam.get("projectId").toString());

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(dto);
    }

    @ResponseBody
    @RequestMapping(value = "/getSetting")
    public JsonResponseDto grrSetting(ServletRequest request, Model model) {
        GRRItemDto dto = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");
            dto = grrTestDataService.searchGRRItem(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(dto);
    }

    @ResponseBody
    @RequestMapping(value = "/getSummarySlot")
    public JsonResponseDto grrSummarySlot(ServletRequest request, Model model) {
        List<AnalysisKeyResultDto> list = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");

//            list = grrTestDataService.searchStationByGRRName(searchParam);
            list = grrTestDataService.searchAnalysisKeys(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(list);
    }

    @ResponseBody
    @RequestMapping(value = "/getSummary")
    public JsonResponseDto grrSummary(ServletRequest request, Model model) {
        List<GRRSummaryDto> list = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");

            list = grrTestDataService.searchGRRSummary(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(list);
    }

    @ResponseBody
    @RequestMapping(value = "/getAnovaAndSource")
    public JsonResponseDto grrAnovaAndSource(ServletRequest request, Model model) {
        GRRResultDto resultDto = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");

            resultDto = grrTestDataService.searchGRRResult(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(resultDto);
    }

    @ResponseBody
    @RequestMapping(value = "/getGrrTestData")
    public JsonResponseDto grrTestData(ServletRequest request, Model model) {
        List<GRRDataDto> result = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");

            result = grrTestDataService.searchGRRTestData(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(result);
    }

    @ResponseBody
    @RequestMapping(value = "/saveGrrTestData")
    public JsonResponseDto grrSaveTestData(ServletRequest request, Model model) {
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");
            grrTestDataService.updateCacheGRRItem(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS();
    }


    @ResponseBody
    @RequestMapping(value = "/getChoiceTestItem")
    public JsonResponseDto grrChoiceTestItem(ServletRequest request, Model model) {
        List<BaseDto> result = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");

            result = grrTestDataService.searchDistinctTestItemName(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(result);
    }

    @ResponseBody
    @RequestMapping(value = "/getChartData")
    public JsonResponseDto grrChartData(ServletRequest request, Model model) {
        GRRChartDto result = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");

            result = grrTestDataService.searchGRRChart(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(result);
    }

    @ResponseBody
    @RequestMapping(value = "/saveChoiceTestItem")
    public JsonResponseDto saveChoiceTestItem(ServletRequest request, Model model) {
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");
            grrTestDataService.updateCacheGRRItem(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS();
    }

    @ResponseBody
    @RequestMapping(value = "/deleteGrrItem")
    public JsonResponseDto deleteGrrItem(ServletRequest request, Model model) {
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:delete")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");
            String grrName = (String) searchParam.get(Constant.GRR_NAME);
            String projectId = (String) searchParam.get(Constant.GLOBAL_PROJECT_ID);

            grrTestDataService.deleteGRRTestData(grrName, projectId);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS();
    }

    @ResponseBody
    @RequestMapping(value = "checkGrrName", method = RequestMethod.POST)
    public JsonResponseDto checkGrrName(HttpServletRequest request) {
        Subject subject = SecurityUtils.getSubject();
        if (!subject.isPermitted("analysis:grr:import")) {
            return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
        }

        Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");
        String grrName = (String) searchParam.get(Constant.GRR_NAME);
        String projectId = (String) searchParam.get(Constant.GLOBAL_PROJECT_ID);
        boolean isExist = false;
        try {
            isExist = grrTestDataService.checkGRRName(grrName, projectId);
        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(!isExist);
    }

    @ResponseBody
    @RequestMapping(value = "/refreshGrrSummary")
    public JsonResponseDto refreshSummary(ServletRequest request, Model model) {
        GRRSummaryDto result = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");
            result = grrTestDataService.refreshGRRSummary(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(result);
    }

    @ResponseBody
    @RequestMapping(value = "/refreshGrrResult")
    public JsonResponseDto refreshAnovaAndSource(ServletRequest request, Model model) {
        GRRResultDto result = null;
        try {
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isPermitted("analysis:grr:view")) {
                return JsonResponseDto.FAILURE().setMessage(ExceptionMessages.EXCEPTION_NO_PERMISSION);
            }

            Map<String, Object> searchParam = Servlets.getParametersStartingWith(request, "search_");
            result = grrTestDataService.refreshGRRResult(searchParam);

        } catch (ApplicationException ex) {
            return JsonResponseDto.FAILURE().setMessage(ex.getMessage());
        }

        return JsonResponseDto.SUCCESS().setBody(result);
    }

    @RequestMapping(value = "/import", method = RequestMethod.POST)
    public ModelAndView dataImport(HttpServletRequest request, HttpServletResponse response) {

        Subject subject = SecurityUtils.getSubject();
        Long userId = securityService.getCurrentUser().getId();
        if (!subject.isPermitted("analysis:grr:import")) {
            return new ModelAndView("error/noPermission");
        }

        Map<Double, Double> mapProcess = new HashMap<Double, Double>();
        ModelAndView mv = new ModelAndView();
        try {
            boolean isMultipart = ServletFileUpload.isMultipartContent(request);
            if (!isMultipart) {
                return mv;
            }
            final HttpSession session = request.getSession();


            FileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            upload.setHeaderEncoding("UTF-8");
            upload.setProgressListener(new ProgressListener() {
                public void update(long pBytesRead, long pContentLength, int pItems) {
                    fileSize = pContentLength;
                }
            });

            List<FileItem> items = upload.parseRequest(request);
            String projectId = "";
            String importType = "";
            String testStrategy = "";
            String operatorValue = "";
            String trialValue = "";
            String partValue = "";
            String grrName = "";
            String soltkey = null;
            String bindGroup1 = null;
            String bindGroup2 = null;
            String bindAttrPart = null;
            String bindAttrOperator = null;

            String bindGroup1_default = "false";
            String bindGroup2_default = "false";
            String bindAttrPart_default = "false";
            String bindAttrOperator_default = "false";

            StringBuffer buffer = new StringBuffer();

            String dirPath = buffer.append(File.separator)
                    .append(ApplicationUtil.getProjectPathSeparator())
                    .append("upload")
                    .append(File.separator).toString();
            String fileName = "";

            for (FileItem item : items) {
                if (item.isFormField()) {
                    if (item.getFieldName().equalsIgnoreCase("projectId")) {
                        projectId = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("importType")) {
                        importType = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("firstChange")) {
                        testStrategy = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("slotGroup")) {
                        testStrategy = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("operatorValue")) {
                        operatorValue = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("trialValue")) {
                        trialValue = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("partValue")) {
                        partValue = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("grrName")) {
                        grrName = item.getString("utf-8");
                    }
                    if (item.getFieldName().equalsIgnoreCase("soltkey")) {
                        soltkey = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("bindGroup1")) {
                        bindGroup1 = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("bindGroup2")) {
                        bindGroup2 = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("bindAttrPart")) {
                        bindAttrPart = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("bindAttrOperator")) {
                        bindAttrOperator = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("bindGroup1_default")) {
                        bindGroup1_default = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("bindGroup2_default")) {
                        bindGroup2_default = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("bindAttrPart_default")) {
                        bindAttrPart_default = item.getString();
                    }
                    if (item.getFieldName().equalsIgnoreCase("bindAttrOperator_default")) {
                        bindAttrOperator_default = item.getString();
                    }
                } else {
                    fileName = new Date().getTime() + "_" + item.getName();
                    String filePath = dirPath + fileName;

                    File uploadFile = new File(filePath);
                    if (!uploadFile.exists()) {
                        uploadFile.createNewFile();
                    }
                    item.write(uploadFile);
                }
            }
            String fileType = fileName.substring(fileName.lastIndexOf('.') + 1);

            GRRDataImportParamDto grrDataImportParamDto = new GRRDataImportParamDto();
            grrDataImportParamDto.setFilePath(dirPath + fileName);
            grrDataImportParamDto.setFileSize(fileSize);
            grrDataImportParamDto.setGrrName(grrName);

            grrDataImportParamDto.setOperatorValue(operatorValue);
            grrDataImportParamDto.setTrialValue(trialValue);
            grrDataImportParamDto.setPartValue(partValue);
            grrDataImportParamDto.setProjectId(projectId);
            AnalysisKeysDto analysisKeysDto = new AnalysisKeysDto();

            analysisKeysDto.setPartKey(bindAttrPart);
            analysisKeysDto.setGroup1Key(bindGroup1);
            analysisKeysDto.setGroup2Key(bindGroup2);

            analysisKeysDto.setDimensionKey(bindAttrOperator);
            analysisKeysDto.setDimensionValue(testStrategy);

            analysisKeysDto.setGroup1KeyFlag(Boolean.valueOf(bindGroup1_default));
            analysisKeysDto.setGroup2KeyFlag(Boolean.valueOf(bindGroup2_default));
            analysisKeysDto.setPartKeyFlag(Boolean.valueOf(bindAttrPart_default));
            analysisKeysDto.setDimensionKeyFlag(Boolean.valueOf(bindAttrOperator_default));

            System.out.println(Boolean.valueOf(bindGroup1_default));
            grrDataImportParamDto.setAnalysisKeysDto(analysisKeysDto);

            if (fileType.equals("csv")) {
                grrDataIOService.importGRRDataFromCvs(grrDataImportParamDto, getProcessEvent(userId, Long.valueOf(soltkey)));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mv;
    }

    private ProcessEvent getProcessEvent(Long userId, Long soltkey) {
        return new ProcessEvent() {
            @Override
            public void update(double rate, String log, long rowReadSize, boolean isLastUpdate) {
                ProcessInfo pri = new ProcessInfo();
                pri.setRate(rate);
                pri.setLog(pri.getLog() + log);
                pri.setLastUpdate(isLastUpdate);
                pri.setReadSize(rowReadSize);
                pri.setTotalSize(fileSize);
                sendListenerResponse(pri, userId, soltkey);
            }
        };

    }

    private void sendListenerResponse(ProcessInfo response, Long userId, Long soltkey) {
        if (response == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        response.setTarget(Constant.UPLOAD_TARGET_GRR);
        JsonMapper mapper = new JsonMapper();
        String json = mapper.toJson(response);

        msgTemplate.setUserDestinationPrefix("/data/");
        msgTemplate.convertAndSend("/topic/data/importListener#" + soltkey + "#" + userId, json);
    }

    public long getFileSize() {
        return fileSize;
    }

    public void setFileSize(long fileSize) {
        this.fileSize = fileSize;
    }

    public long getReadSize() {
        return readSize;
    }

    public void setReadSize(long readSize) {
        this.readSize = readSize;
    }
}
